// +----------------------------------------------------------------------
// | EasyGoAdmin敏捷开发框架 [ 赋能开发者，助力企业发展 ]
// +----------------------------------------------------------------------
// | 版权所有 2019~2022 深圳EasyGoAdmin研发中心
// +----------------------------------------------------------------------
// | Licensed LGPL-3.0 EasyGoAdmin并不是自由软件，未经许可禁止去掉相关版权
// +----------------------------------------------------------------------
// | 官方网站: http://www.easygoadmin.vip
// +----------------------------------------------------------------------
// | Author: @半城风雨 团队荣誉出品
// +----------------------------------------------------------------------
// | 版权和免责声明:
// | 本团队对该软件框架产品拥有知识产权（包括但不限于商标权、专利权、著作权、商业秘密等）
// | 均受到相关法律法规的保护，任何个人、组织和单位不得在未经本团队书面授权的情况下对所授权
// | 软件框架产品本身申请相关的知识产权，禁止用于任何违法、侵害他人合法权益等恶意的行为，禁
// | 止用于任何违反我国法律法规的一切项目研发，任何个人、组织和单位用于项目研发而产生的任何
// | 意外、疏忽、合约毁坏、诽谤、版权或知识产权侵犯及其造成的损失 (包括但不限于直接、间接、
// | 附带或衍生的损失等)，本团队不承担任何法律责任，本软件框架禁止任何单位和个人、组织用于
// | 任何违法、侵害他人合法利益等恶意的行为，如有发现违规、违法的犯罪行为，本团队将无条件配
// | 合公安机关调查取证同时保留一切以法律手段起诉的权利，本软件框架只能用于公司和个人内部的
// | 法律所允许的合法合规的软件产品研发，详细声明内容请阅读《框架免责声明》附件；
// +----------------------------------------------------------------------

/**
 * 数据库连接工具
 * @author 半城风雨
 * @since 2021/9/8
 * @File : db
 */
package utils

import (
	"easygoadmin/app/model"
	"easygoadmin/conf"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/kataras/iris/v12"
	"github.com/kataras/iris/v12/sessions"
	"github.com/kataras/iris/v12/sessions/sessiondb/redis"
	"time"
	"xorm.io/core"
	"xorm.io/xorm" //"github.com/go-xorm/xorm"
	"xorm.io/xorm/log"
)

var XormDb *xorm.Engine
var RedisDb *redis.Database
var Sess *sessions.Sessions

func init() {
	fmt.Println("初始化并连接数据库")

	// 获取配置实例
	var err error
	dataSourceName := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&timeout=3s&parseTime=true", conf.CONFIG.Mysql.Username, conf.CONFIG.Mysql.Password, conf.CONFIG.Mysql.Host, conf.CONFIG.Mysql.Port, conf.CONFIG.Mysql.Database, conf.CONFIG.Mysql.Charset)
	XormDb, err = xorm.NewEngine("mysql", dataSourceName)
	if err != nil {
		fmt.Printf("数据库连接错误:%v", err.Error())
		return
	}

	// 通过engine.Ping()来进行数据库的连接测试是否可以连接到数据库。
	err = XormDb.Ping()
	if err == nil {
		fmt.Println("数据库连接成功")
		//关闭连接
		//defer XormDb.Close()
	} else {
		fmt.Printf("数据库连接错误:%v", err.Error())
		return
	}

	XormDb.DatabaseTZ = time.Local // 必须
	XormDb.TZLocation = time.Local // 必须
	// 设置连接池的空闲数大小
	XormDb.SetMaxIdleConns(10)
	// 设置最大打开连接数
	XormDb.SetMaxOpenConns(30)

	//XormDb.SetMapper(names.GonicMapper{})//jordan
	// 结构体与数据表的映射
	tbMapper := core.NewPrefixMapper(core.SnakeMapper{}, "sys_")  // user 结构体 对应 sys_user table
	XormDb.SetTableMapper(tbMapper)
	// 加后缀
	//names.NewSuffixMapper(names.SnakeMapper{}, "suffix")

	//同步数据库结构  from code to mysql database table
	XormDb.Sync2(new(model.User),new(model.UserRole),new(model.Level))
	XormDb.Sync2(new(model.Item),new(model.ItemCate))
	XormDb.Sync2(new(model.Member),new(model.MemberLevel))

	XormDb.Sync2(new(model.Menu),new(model.Role),new(model.RoleMenu))
	XormDb.Sync2(new(model.Config),new(model.ConfigData))

	XormDb.Sync2(new(model.Dept),new(model.City))
	XormDb.Sync2(new(model.Dict),new(model.DictData))

	XormDb.Sync2(new(model.Example),new(model.Example2))
	XormDb.Sync2(new(model.Ad),new(model.AdSort))

	XormDb.Sync2(new(model.Position))
	XormDb.Sync2(new(model.Link))
	XormDb.Sync2(new(model.Notice))




	// 开启调试模式和打印日志,会在控制台打印执行的sql
	if conf.CONFIG.Mysql.Debug {
		XormDb.ShowSQL(conf.CONFIG.Mysql.Debug)
		XormDb.SetLogLevel (log.LOG_DEBUG)
	}
}
func init() {
	RedisDb = GetRedisDB()
	// Optionally configure the underline driver:
	// driver := redis.GoRedis()
	// driver.ClientOptions = redis.Options{...}
	// driver.ClusterOptions = redis.ClusterOptions{...}
	// RedisDb.New(redis.Config{Driver: driver, ...})
	//defer RedisDb.Close() // close the database connection if application errored.
	Sess = sessions.New(sessions.Config{
		Cookie:          "_session_id",
		Expires:         0, // defaults to 0: unlimited life. Another good value is: 45 * time.Minute,
		AllowReclaim:    true,
		CookieSecureTLS: true,
	})

	//
	// IMPORTANT:
	//
	Sess.UseDatabase(RedisDb)
	//程序中断时，将数据库关闭
	iris.RegisterOnInterrupt(func() {
		defer RedisDb.Close()
	})
	//app := example.NewApp(sess)
	//
	//// TIP scaling-out Iris sessions using redis:
	//// $ docker-compose up
	//// http://localhost:8080/set/$key/$value
	//// The value will be available on all Iris servers as well.
	//// E.g. http://localhost:9090/get/$key and vice versa.
	//addr := fmt.Sprintf(":%s", getenv("PORT", "8080"))
	//app.Listen(addr)
}

// Redis数据库
func GetRedisDB() *redis.Database {
	redis := redis.New(initRedisConfig())
	if redis == nil {
		panic("Redis缓存数据库连接错误")
	}

	return redis
}

//初始化配置项
func initRedisConfig() redis.Config {

	//默认配置
	config := redis.DefaultConfig()
	// 网络
	if conf.CONFIG.Redis.Network != "" {
		config.Network = conf.CONFIG.Redis.Network
	}
	// 地址
	if conf.CONFIG.Redis.Addr != "" {
		config.Addr = conf.CONFIG.Redis.Addr
	}
	// 超时时间
	if conf.CONFIG.Redis.Timeout > 0 {
		config.Timeout = time.Duration(conf.CONFIG.Redis.Timeout) * time.Second
	}
	// MaxActive
	if conf.CONFIG.Redis.MaxActive > 0 {
		config.MaxActive = conf.CONFIG.Redis.MaxActive
	}
	// 密码
	if conf.CONFIG.Redis.Password != "" {
		config.Password = conf.CONFIG.Redis.Password
	}
	// 数据库
	if conf.CONFIG.Redis.Database != "" {
		config.Database = conf.CONFIG.Redis.Database
	}
	// 前缀
	if conf.CONFIG.Redis.Prefix != "" {
		config.Prefix = conf.CONFIG.Redis.Prefix
	}

	return config
}

/*

xorm 内置了三种 Mapper 实现:
SnakeMapper 支持struct为驼峰式命名，表结构为下划线命名之间的转换，这个是默认的Maper； // user_table——UserTable，user_id——UserId
SameMapper 支持结构体名称和对应的表名称以及结构体field名称与对应的表字段名称相同的命名；
GonicMapper 和SnakeMapper很类似，但是对于特定词支持更好，比如ID会翻译成id而不是i_d。

表名的优先级顺序如下：
engine.Table() 指定的临时表名优先级最高
TableName() string 其次
Mapper 自动映射的表名优先级最后

字段名的优先级顺序如下:
结构体tag指定的字段名优先级较高  xorm:"'column_name'"
Mapper 自动映射的表名优先级较低

数据类型对应规则：
Go中的Type类型	                                         XORM映射的Type类型
implemented Conversion	                                 Text
int, int8, int16, int32, uint, uint8, uint16, uint32	 Int
int64, uint64	                                         BigInt
float32	                                                 Float
float64	                                                 Double
complex64, complex128	                                 Varchar(64)
[]uint8	                                                 Blob
array, slice, map except []uint8	                     Text
bool	                                                 Bool
string	                                                 Varchar(255)
time.Time	                                             DateTime
cascade struct	                                         BigInt
struct	                                                 Text
Others	                                                 Text


2.3.6 xorm对数据类型的定义
name	                        当前field对应的字段的名称，可选，如不写，则自动根据field名字和转换规则命名
pk	                            是否是Primary Key
autoincr	                    是否是自增
[not ]null 或 notnull	        是否可以为空
unique	                        是否是唯一
index	                        是否是索引
extends	                        应用于一个匿名成员结构体或者非匿名成员结构体之上
-	                             Field将不进行字段映射
->	                            Field将只写入到数据库而不从数据库读取
<-	                            Field将只从数据库读取，而不写入到数据库
created	                        Field将在Insert时自动赋值为当前时间
updated	                        Field将在Insert或Update时自动赋值为当前时间
deleted	                        Field将在Delete时设置为当前时间，并且当前记录不删除
version	                        Field将会在insert时默认为1，每次更新自动加1
default 0或default(0)	        设置默认值，紧跟的内容如果是Varchar等需要加上单引号
json	                        表示内容将先转成Json格式，然后存储到数据库中，数据库中的字段类型可以为Text或者二进制
comment	                        设置字段的注释（当前仅支持mysql）

原文链接：https://blog.csdn.net/qq_42647903/article/details/126143046

*/
